import React, {
  useState,
  forwardRef,
  useImperativeHandle,
  useRef,
  useEffect,
} from "react";
import { Icon } from "@iconify/react";
import styled from "styled-components";
import { flushSync } from "react-dom";
import { debounce } from "@/utils/common/common";
import useSyncCallback from "@/hooks/useSyncCallback";
import useGetState from "@/hooks/useGetState";

const Styled = styled.div`
  height: 100%;
  .wrapper {
    display: flex;
    background-color: #fff;
    height: 100%;
    z-index: 9;
    overflow: hidden;
    position: relative;

    .content {
      padding: 0 10px;
      display: flex;
      align-items: center;
      flex-wrap: nowrap;
      transition: transform 0.5s;
      &.overflow {
        padding-left: 30px;
        padding-right: 30px;
      }
    }
    .left,
    .right {
      background-color: #fff;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto;
      width: 20px;
      height: 35px;
      display: flex;
      align-items: center;
      justify-content: center;

      font-size: 18px;
      border: 1px solid #e0e0e6;
      border-radius: 2px;

      z-index: 2;
      cursor: pointer;
    }
    .left {
      left: 0;
    }
    .right {
      right: 0;
    }
  }
`;

const ScrollX = forwardRef((props, ref) => {
  const children = React.Children.toArray(props.children);
  let showArrow = props?.showArrow || true;
  const [translateX, setTranslateX] = useState(0);
  const [isOverflow, setIsOverflow] = useState(false);
  const wrapper = useRef();
  const content = useRef();

  const resetTranslateX = useSyncCallback(
    debounce((wrapperWidth, contentWidth) => {
      if (!isOverflow) {
        //未溢出的情况不移动
        setTranslateX(0);
      } else if (-translateX > contentWidth - wrapperWidth) {
        let data = wrapperWidth - contentWidth;
        setTranslateX(data);
      } else if (translateX > 0) {
        setTranslateX(0);
      } else {
        setTranslateX(translateX);
      }
    }, 200)
  );

  const refreshIsOverflow = debounce(() => {
    const wrapperWidth = wrapper.current?.offsetWidth;
    const contentWidth = content.current?.offsetWidth;
    //判断溢出----内容大于容器
    if (contentWidth > wrapperWidth) {
      setIsOverflow(true);
    } else {
      setIsOverflow(false);
    }

    resetTranslateX(wrapperWidth, contentWidth);
  }, 200);

  const handleScroll = (x, width) => {
    const wrapperWidth = wrapper.current?.offsetWidth;
    const contentWidth = content.current?.offsetWidth;

    if (contentWidth <= wrapperWidth) return; //代表当前已有标签并未超过容纳区域

    //x小于最小范围
    if (x < -translateX + 150) {
      flushSync(() => {
        let data = -(x - 150);
        setTranslateX(data);
      });
      resetTranslateX(wrapperWidth, contentWidth);
    }
    //当x大于最大值
    if (x + width > -translateX + wrapperWidth) {
      flushSync(() => {
        let data = wrapperWidth - (x + width);
        setTranslateX(data);
      });
      resetTranslateX(wrapperWidth, contentWidth);
    }
  };

  const handleMouseWheel = (e) => {
    // if (e.preventDefault) e.preventDefault(); //通过滚轮移动的时候阻止默认行为
    //当内容超出容器大小时候会显示的左右箭头，给其绑定回调
    const { wheelDelta } = e;
    const wrapperWidth = wrapper.current?.offsetWidth;
    const contentWidth = content.current?.offsetWidth;
    /*
     * @wheelDelta 平行滚动的值 >0： 右移  <0: 左移
     * @translateX 内容translateX的值
     * @wrapperWidth 容器的宽度
     * @contentWidth 内容的宽度
     */
    if (wheelDelta < 0) {
      if (wrapperWidth > contentWidth && translateX < -10) return;
      if (
        wrapperWidth <= contentWidth &&
        contentWidth + translateX - wrapperWidth < -10
      )
        return;
    }
    if (wheelDelta > 0 && translateX > 10) return;
    flushSync(() => {
      let data = translateX + wheelDelta;
      setTranslateX(data);
    });
    resetTranslateX(wrapperWidth, contentWidth);
  };

  //监听指定的dom，当dom发生改变的时候会执行回调函数
  const observe = new MutationObserver(refreshIsOverflow);

  useEffect(() => {
    //组件挂载的时候做的内容
    refreshIsOverflow();
    window.addEventListener("resize", refreshIsOverflow);
    //监听内容宽度刷新是否超出
    observe.observe(content.current, { childList: true });

    return function () {
      //组件卸载前做的内容
      window.removeEventListener("resize", refreshIsOverflow);
      observe.disconnect();
    };
  }, []);

  //向外暴露组件内部方法
  useImperativeHandle(ref, () => {
    return {
      handleScroll,
    };
  });

  return (
    <Styled>
      <div className="wrapper" ref={wrapper} onWheel={handleMouseWheel}>
        {showArrow && isOverflow ? (
          <>
            <div
              className="left"
              onClick={handleMouseWheel.bind(null, { wheelDelta: 120 })}
            >
              <Icon icon="ic:sharp-arrow-left" />
            </div>
            <div
              className="right"
              onClick={handleMouseWheel.bind(null, { wheelDelta: -120 })}
            >
              <Icon icon="ic:sharp-arrow-right" />
            </div>
          </>
        ) : null}
        <div
          ref={content}
          className={`content ${isOverflow && showArrow ? "overflow" : ""}`}
          style={{ transform: `translateX(${translateX}px)` }}
        >
          {children.length > 0 ? children : null}
        </div>
      </div>
    </Styled>
  );
});

export default ScrollX;
